﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace lucere.entity
{
    /// <summary>Documents are the unit of indexing and search.
    /// 
    /// A Document is a set of fields.  Each field has a name and a textual value.
    /// A field may be {@link Fieldable#IsStored() stored} with the document, in which
    /// case it is returned with search hits on the document.  Thus each document
    /// should typically contain one or more stored fields which uniquely identify
    /// it.
    /// 
    /// <p/>Note that fields which are <i>not</i> {@link Fieldable#IsStored() stored} are
    /// <i>not</i> available in documents retrieved from the index, e.g. with {@link
    /// ScoreDoc#doc}, {@link Searcher#Doc(int)} or {@link
    /// IndexReader#Document(int)}.
    /// </summary>
    public interface IDocument : ISerializable
    {
        /// <summary>Returns a List of all the fields in a document.
        /// <p/>Note that fields which are <i>not</i> {@link Fieldable#IsStored() stored} are
        /// <i>not</i> available in documents retrieved from the
        /// index, e.g. {@link Searcher#Doc(int)} or {@link
        /// IndexReader#Document(int)}.
        /// </summary>
        List<IField> Fields { get; }
        /// <summary>Gets/Sets a boost factor for hits on any field of this document.  This value
        /// will be multiplied into the score of all hits on this document.
        /// 
        /// <p/>The default value is 1.0.
        /// 
        /// <p/>Values are multiplied into the value of {@link Fieldable#GetBoost()} of
        /// each field in this document.  Thus, this method in effect sets a default
        /// boost for the fields of this document.
        /// 
        /// <p/>Note that once a document is indexed this value is no longer available
        /// from the index.  At search time, for retrieved documents, this method always 
        /// returns 1. This however does not mean that the boost value set at  indexing 
        /// time was ignored - it was just combined with other indexing time factors and 
        /// stored elsewhere, for better indexing and search performance. (For more 
        /// information see the "norm(t,d)" part of the scoring formula in 
        /// {@link Lucene.Net.Search.Similarity Similarity}.)
        /// </summary>
        float Boost { get; set; }

        /// <summary> <p/>Adds a field to a document.  Several fields may be added with
        /// the same name.  In this case, if the fields are indexed, their text is
        /// treated as though appended for the purposes of search.<p/>
        /// <p/> Note that add like the removeField(s) methods only makes sense 
        /// prior to adding a document to an index. These methods cannot
        /// be used to change the content of an existing index! In order to achieve this,
        /// a document has to be deleted from an index and a new changed version of that
        /// document has to be added.<p/>
        /// </summary>
        void Add(IFieldable field);
        /// <summary> <p/>Removes field with the specified name from the document.
        /// If multiple fields exist with this name, this method removes the first field that has been added.
        /// If there is no field with the specified name, the document remains unchanged.<p/>
        /// <p/> Note that the removeField(s) methods like the add method only make sense 
        /// prior to adding a document to an index. These methods cannot
        /// be used to change the content of an existing index! In order to achieve this,
        /// a document has to be deleted from an index and a new changed version of that
        /// document has to be added.<p/>
        /// </summary>
        void RemoveField(string fieldName);
        /// <summary> <p/>Removes all fields with the given name from the document.
        /// If there is no field with the specified name, the document remains unchanged.<p/>
        /// <p/> Note that the removeField(s) methods like the add method only make sense 
        /// prior to adding a document to an index. These methods cannot
        /// be used to change the content of an existing index! In order to achieve this,
        /// a document has to be deleted from an index and a new changed version of that
        /// document has to be added.<p/>
        /// </summary>
        void RemoveFields(string fieldName);

        /// <summary>Returns a field with the given name if any exist in this document, or
        /// null.  If multiple fields exists with this name, this method returns the
        /// first value added.
        /// Do not use this method with lazy loaded fields.
        /// </summary>
        IField GetField(string fieldName);
        /// <summary>Returns a field with the given name if any exist in this document, or
        /// null.  If multiple fields exists with this name, this method returns the
        /// first value added.
        /// </summary>
        IFieldable GetFieldable(string fieldName);

        /// <summary>Returns the string value of the field with the given name if any exist in
        /// this document, or null.  If multiple fields exist with this name, this
        /// method returns the first value added. If only binary fields with this name
        /// exist, returns null.
        /// </summary>
        string Get(string fieldName);
        /// <summary> Returns an array of values of the field specified as the method parameter.
        /// This method returns an empty array when there are no
        /// matching fields.  It never returns null.
        /// </summary>
        /// <param name="fieldName">the name of the field
        /// </param>
        /// <returns> a <code>String[]</code> of field values
        /// </returns>
        string[] GetValues(string fieldName);

        /// <summary> Returns an array of byte arrays for of the fields that have the name specified
        /// as the method parameter.  This method returns an empty
        /// array when there are no matching fields.  It never
        /// returns null.
        /// 
        /// </summary>
        /// <param name="fieldName">the name of the field
        /// </param>
        /// <returns> a <code>byte[][]</code> of binary field values
        /// </returns>
        byte[] GetBinaryValue(string fieldName);
        /// <summary> Returns an array of bytes for the first (or only) field that has the name
        /// specified as the method parameter. This method will return <code>null</code>
        /// if no binary fields with the specified name are available.
        /// There may be non-binary fields with the same name.
        /// 
        /// </summary>
        /// <param name="fieldName">the name of the field.
        /// </param>
        /// <returns> a <code>byte[]</code> containing the binary field value or <code>null</code>
        /// </returns>
        byte[][] GetBinaryValues(string fieldName);

        /// <summary> Returns an array of {@link Field}s with the given name.
        /// Do not use with lazy loaded fields.
        /// This method returns an empty array when there are no
        /// matching fields.  It never returns null.
        /// 
        /// </summary>
        /// <param name="fieldName">the name of the field
        /// </param>
        /// <returns> a <code>Field[]</code> array
        /// </returns>
        IField[] GetFields(string fieldName);
        /// <summary> Returns an array of {@link Fieldable}s with the given name.
        /// This method returns an empty array when there are no
        /// matching fields.  It never returns null.
        /// 
        /// </summary>
        /// <param name="fieldName">the name of the field
        /// </param>
        /// <returns> a <code>Fieldable[]</code> array
        /// </returns>
        IFieldable[] GetFieldables(string fieldName);
    }
}
